/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package huffman;

import arbre.ArbreHuffman;
import arbre.NoeudFeuille;
import arbre.NoeudInterne;
import fileNoeud.FilePrioriteeDeNoeud;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Iterator;
import java.util.LinkedHashMap;

/**
 *
 * @author ksz
 */
public class DecoderFichier {

    private String nomFichier;
    private String nomFichierDecode;
    private LinkedHashMap dictionnaireFequences;
    private FilePrioriteeDeNoeud file;
    private ArbreHuffman arbre;
    private byte[] tamponLecture;

    public DecoderFichier(String nomFichier) {

        this.nomFichier = nomFichier;
        this.nomFichierDecode = nomFichier.substring(0, nomFichier.length() - 3);
        file = new FilePrioriteeDeNoeud();
        arbre = new ArbreHuffman();
        tamponLecture = new byte[256];
        System.out.println("Nom fichier decodé : " + nomFichierDecode);
        construireFichierDecode();

    }

    private void construireFichierDecode() {
        try {

            ObjectInputStream entree = new ObjectInputStream(new FileInputStream(nomFichier));

            File fichier = new File(nomFichierDecode);

            if (fichier.exists()) {
                fichier.delete();
            }

            fichier.createNewFile();

            BufferedOutputStream fichierDecode = new BufferedOutputStream(new FileOutputStream(nomFichierDecode));

            dictionnaireFequences = (LinkedHashMap) entree.readObject();

            // on recupere le nombre de caractères pour s'arreter quand il faut
            int nbCaracteres = getNombreDeCaracteres();

            int compteurCaracteres = 0;

            System.out.println("Nombre de caracteres : " + nbCaracteres);

            file.construireFilePrioritee(dictionnaireFequences);

            arbre.construireArbre(file);

            arbre.afficherBitsCode();

            int tailleLu = entree.read(tamponLecture);

            NoeudInterne parcours = arbre.getRacine();

            // on va parcourir tout le fichier coder et convertir chaque bits code par le
            // caractères associés.
            while (tailleLu != -1) {

                for(int j=0; j < tailleLu; j++) {

                    StringBuilder code = new StringBuilder(Integer.toBinaryString((int)tamponLecture[j]));


                    // pour les nombres négatifs on recupere les 8 bits de poid faible
                    if (code.length() > 8) {
                        code = new StringBuilder(code.substring(code.length() - 8));

                    }

                    while (code.length() < 8) {
                        code.insert(0, "0");
                    }


                    int i=0;

                    while( i < code.length() && compteurCaracteres < nbCaracteres) {

                        if (code.charAt(i) == '0' && parcours.getFilsGauche() != null) {

                            if (parcours.getFilsGauche().estFeuille()) {

                                NoeudFeuille nf = (NoeudFeuille) parcours.getFilsGauche();

                                char contenu = (Character) nf.getContenu().getContenu();

                                fichierDecode.write((int) contenu);

                                compteurCaracteres++;

                                parcours = arbre.getRacine();

                            } else {
                                parcours = (NoeudInterne) parcours.getFilsGauche();
                            }

                        } else if (code.charAt(i) == '1' && parcours.getFilsDroit() != null) {

                            if (parcours.getFilsDroit().estFeuille()) {

                                NoeudFeuille nf = (NoeudFeuille) parcours.getFilsDroit();

                                char contenu = (Character) nf.getContenu().getContenu();

                                fichierDecode.write((int) contenu);

                                compteurCaracteres++;
                                
                                parcours = arbre.getRacine();

                            } else {
                                parcours = (NoeudInterne) parcours.getFilsDroit();
                            }

                        }

                        i++;

                    }
                    
                }

                tailleLu = entree.read(tamponLecture);
            }

            System.out.println("Nombre de caracteres : " + compteurCaracteres);

            entree.close();
            fichierDecode.close();

            javax.swing.JOptionPane.showMessageDialog(null, "Le fichier" + nomFichier + " a été décodé");

        } catch (FileNotFoundException ex) {
            javax.swing.JOptionPane.showMessageDialog(null, "Le fichier est introuvable");
        } catch (IOException ex) {
            javax.swing.JOptionPane.showMessageDialog(null, "Impossible de lire le fichier");
        } catch (ClassNotFoundException ex) {
            javax.swing.JOptionPane.showMessageDialog(null, "Impossible de récuperer les informations pour décoder");
            System.out.println("Impossible de récuperer l'arbre");
        }
    }

    private int getNombreDeCaracteres() {
        
        int taille = 0;
        Character key;
        Iterator i = dictionnaireFequences.keySet().iterator();

        while (i.hasNext())
        {
            key = (Character)i.next();

            taille += (Integer)dictionnaireFequences.get(key);
        }

        return taille;

    }
}

